import 'dart:ui' as ui;
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_demo/ui/pages/read/tools/paper_point.dart';

class SideBPainter extends CustomPainter {
  ValueNotifier<PaperPoint> p;
  final Color? bColor;

  SideBPainter(this.p, this.bColor) : super(repaint: p);

  //A 点变化时候会被调用
  @override
  void paint(Canvas canvas, Size size) {
    /// 翻页完毕
    if (p.value.a.y == p.value.f.y) {
      return;
    }

    /// af重合 不需要绘制
    if (p.value.a == p.value.f) {
      return;
    }

    //校验关键点b没有坐标
    if (p.value.b.x.isNaN) {
      return;
    }

    //print("重绘${p.value}");
    canvas.clipRect(Offset.zero & size);
    Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.fill
      ..strokeWidth = 2;
    //保存之前的绘制
    canvas.save();
    //画笔的起点平移到屏幕中心
    canvas.translate(size.width / 2, size.height / 2);
    //前面最近的一个 save() 之间的操作合并到一起
    canvas.restore();
    //mPathAB区域 下一页可见区域+当前页不可见区域
    Path mPathAB = Path();
    mPathAB.moveTo(p.value.c.x, p.value.c.y);
    //从c点到b点以e为控制点画一条二阶贝塞尔弧线，画完后画笔移动到 b
    mPathAB.quadraticBezierTo(
        p.value.e.x, p.value.e.y, p.value.b.x, p.value.b.y);
    //从b点到a点画一条直线
    mPathAB.lineTo(p.value.a.x, p.value.a.y);
    //从a点到k点画一条直线
    mPathAB.lineTo(p.value.k.x, p.value.k.y);
    //从k点到j点以h为控制点画一条二阶贝塞尔弧线,画完后画笔移动到 j
    mPathAB.quadraticBezierTo(
        p.value.h.x, p.value.h.y, p.value.j.x, p.value.j.y);
    mPathAB.lineTo(p.value.f.x, p.value.f.y);
    mPathAB.close();
    //将adi连接成三角形区域，为了分割AB面
    Path mPath1 = Path();
    mPath1.moveTo(p.value.d.x, p.value.d.y);
    mPath1.lineTo(p.value.a.x, p.value.a.y);
    mPath1.lineTo(p.value.i.x, p.value.i.y);
    mPath1.close();
    //B区域 当前页不可见区域
    //PathOperation.intersect 两个区域重合的部分取出来
    Path mPathB = Path.combine(PathOperation.intersect, mPathAB, mPath1);
    //B面着色
    canvas.drawPath(mPathB, paint..color = bColor ?? Colors.grey.shade400);

    //画阴影
    drawShadow(canvas, mPathAB, mPathB, paint);
    //左上右上阴影间隔的缺角，补足之
    recoupUpperShadow(canvas, paint);
  }

  @override
  bool shouldRepaint(covariant SideBPainter oldDelegate) {
    return oldDelegate.p != p;
  }

  void drawShadow(Canvas canvas, Path mPathAB, Path mPathB, Paint paint) {
    //处理左上阴影
    //求a点之外p点的偏移量
    double m1 = (p.value.a.x - p.value.p.x);
    double n1 = (p.value.a.y - p.value.p.y);
    //根据偏移量画出 AB-pyy1 = 阴影区域（注意包括k、f否则有缺角）
    Path pyy1 = Path();
    pyy1.moveTo(p.value.c.x - m1, p.value.c.y);
    pyy1.quadraticBezierTo(
        p.value.e.x - m1, p.value.e.y - n1, p.value.b.x - m1, p.value.b.y - n1);
    pyy1.lineTo(p.value.p.x, p.value.p.y);
    pyy1.lineTo(p.value.k.x, p.value.k.y);
    pyy1.lineTo(p.value.f.x, p.value.f.y);
    pyy1.close();
    //处理右上阴影(和左上同理)
    double mE1 = (p.value.a.x - p.value.p2.x);
    double nE1 = (p.value.a.y - p.value.p2.y); // 负数

    Path pyy2 = Path();
    pyy2.moveTo(p.value.j.x, (p.value.j.y - nE1));
    pyy2.quadraticBezierTo(p.value.i.x - mE1, p.value.i.y - nE1,
        p.value.k.x - mE1, p.value.k.y - nE1);
    pyy2.lineTo(p.value.p2.x, p.value.p2.y);
    pyy2.lineTo(p.value.b.x, p.value.b.y);
    pyy2.lineTo(p.value.f.x, p.value.f.y);
    pyy2.close();

    Path startYY = Path.combine(PathOperation.reverseDifference, mPathAB, pyy1);
    Paint paint2 = Paint();
    // 上左阴影
    canvas.drawPath(
        startYY,
        paint2
          ..style = PaintingStyle.fill
          ..shader = ui.Gradient.linear(
              Offset(p.value.a.x, p.value.a.y),
              Offset(p.value.p.x, p.value.p.y),
              [Colors.black12, Colors.transparent]));
    Path endYY = Path.combine(PathOperation.reverseDifference, mPathAB, pyy2);
    //上右阴影
    canvas.drawPath(
        endYY,
        paint2
          ..style = PaintingStyle.fill
          ..shader = ui.Gradient.linear(
              Offset(p.value.a.x, p.value.a.y),
              Offset(p.value.p2.x, p.value.p2.y),
              [Colors.black12, Colors.transparent]));

    // 右下阴影
    Path pr = Path();
    pr.moveTo(p.value.c.x, p.value.c.y);
    pr.lineTo(p.value.j.x, p.value.j.y);
    pr.lineTo(p.value.h.x, p.value.h.y);
    pr.lineTo(p.value.e.x, p.value.e.y);
    pr.close();
    Path p1 = Path.combine(PathOperation.intersect, pr, mPathAB);
    Path p2 = Path.combine(PathOperation.difference, p1, mPathB);

    Offset u = Offset(
        PaperPoint.toTwoPoint(p.value.a, p.value.f, p.value.d, p.value.i).x,
        PaperPoint.toTwoPoint(p.value.a, p.value.f, p.value.d, p.value.i).y);
    canvas.drawPath(
        p2,
        paint
          ..style = PaintingStyle.fill
          ..shader = ui.Gradient.linear(u, Offset(p.value.g.x, p.value.g.y),
              [Colors.black26, Colors.transparent]));
  }

  ///左上右上阴影间隔的缺角，补足之
  void recoupUpperShadow(Canvas canvas, Paint paint) {
    double m1 = (p.value.a.x - p.value.p.x);
    double n1 = (p.value.a.y - p.value.p.y);
    double mE1 = (p.value.a.x - p.value.p2.x);
    double nE1 = (p.value.a.y - p.value.p2.y); // 负数

    var twoPoint = PaperPoint.toTwoPoint(
        Point(p.value.b.x - m1, p.value.b.y - n1),
        p.value.p,
        p.value.p2,
        Point(p.value.k.x - mE1, p.value.k.y - nE1));

    Path pd = Path();
    pd.moveTo(p.value.a.x, p.value.a.y);
    pd.lineTo(twoPoint.x, twoPoint.y);
    pd.lineTo(p.value.p2.x, p.value.p2.y);

    pd.close();
    canvas.drawPath(
        pd,
        paint
          ..shader = ui.Gradient.linear(
            Offset(p.value.a.x, p.value.a.y),
            Offset(p.value.p2.x, p.value.p2.y),
            [Colors.black12, Colors.transparent],
          )
          ..style = PaintingStyle.fill);

    Path ps = Path();
    ps.moveTo(p.value.a.x, p.value.a.y);
    ps.lineTo(twoPoint.x, twoPoint.y);
    ps.lineTo(p.value.p.x, p.value.p.y);
    ps.close();

    canvas.drawPath(
        ps,
        paint
          ..shader = ui.Gradient.linear(
              Offset(p.value.a.x, p.value.a.y),
              Offset(p.value.p.x, p.value.p.y),
              [Colors.black12, Colors.transparent])
          ..style = PaintingStyle.fill);
  }
}
